﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Cache;
using System.Threading;



namespace SGData
{
    public class SGListener
    {
        #region Logging
        #endregion

        #region Constants
        const string SG_HOME = "http://uk.warrants.com/";
        const string SG_LOGIN = "http://uk.warrants.com/members/login/php_login.php";
        const string SG_HEADER = "http://uk.warrants.com/services/realtime/index.php?family=WARRANT&typeul=INDEX";
        const string SG_PRODUCTS = "http://uk.warrants.com/services/realtime/products.php?family=WARRANT&typeul=INDEX&sense=&ullabel=";
        const string SG_DATA_LIVE = "http://uk.warrants.com/services/realtime/getlive.php?family=WARRANT&typeul=INDEX&sense=&ullabel=";
        const string LOGIN_DETAILS = "email=blah@blah.com&password=blah";
        #endregion

        #region Events
        public delegate void Update(DateTime snapshotDT, SGDataModel.SnapshotDataTable snapshot);

        public event Update DataUpdated;
        #endregion

        #region State

        object _Lock = new object();
        int _Interval;
        string _UserId;
        string _Password;
        CookieContainer _Cookies;
        Thread _ListenerThread;
        bool _Continue = false;

        SGDataModel.SnapshotDataTable _Snapshot;
        #endregion

        #region CtorDtor
        SGListener() {}
        public SGListener(int interval, string userId, string password)
        {
            _Interval = interval;
            _UserId = userId;
            _Password = password;
            _Cookies = new CookieContainer();
        }
        #endregion

        public void Connect()
        {
            // HOME
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(SG_HOME);
            req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
            req.CookieContainer = _Cookies;
            string rsp = GetResponse(req);

            // LOGIN
            req = (HttpWebRequest)WebRequest.Create(SG_LOGIN);
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
            req.CookieContainer = _Cookies;
            Stream stm = req.GetRequestStream();
            byte[] ar = new ASCIIEncoding().GetBytes(LOGIN_DETAILS);
            stm.Write(ar, 0, ar.Length);
            stm.Close();
            rsp = GetResponse(req);

            // HEADER DATA REQUEST
            req = (HttpWebRequest)WebRequest.Create(SG_HEADER);
            req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
            req.CookieContainer = _Cookies;
            rsp = GetResponse(req);

            _Continue = true;
            Listen();
        }

        public void Disconnect()
        {
            _Cookies = null;
        }

        public SGDataModel.SnapshotDataTable Snapshot
        {
            get
            {
                SGDataModel.SnapshotDataTable dt = null;
                lock (_Lock)
                {
                    if (null != _Snapshot)
                    {
                        dt = (SGDataModel.SnapshotDataTable)_Snapshot.Copy();
                    }
                }
                return dt;
            }
        }

        void Listen()
        {
            _ListenerThread = new Thread(new ThreadStart(ThreadProc));
            _ListenerThread.IsBackground = true;
            _ListenerThread.Start();
        }
        void ThreadProc()
        {
            // FIRST DATA REQUEST
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(SG_PRODUCTS);
            req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
            req.CookieContainer = _Cookies;
            string rsp = GetResponse(req);

            SGDataModel.SnapshotDataTable snap = GetProducts(rsp);
            if (null != snap)
            {
                lock (_Lock)
                {
                    _Snapshot = snap;
                }
            }

            while (_Continue)
            {
                DateTime snapDateTime = DateTime.Now;

                // GET LIVE DATA
                req = (HttpWebRequest)WebRequest.Create(SG_DATA_LIVE);
                req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
                req.CookieContainer = _Cookies;
                rsp = GetResponse(req);

                SGDataModel.SnapshotDataTable newData = GetPriceUpdates(rsp);

                Update updates = DataUpdated;
                if (null != updates)
                {
                    lock(_Lock)
                    {
                        updates(snapDateTime, newData);
                    }
                }

                Thread.Sleep(_Interval*1000);
            }
        }

        #region Process Response

        static string GetResponse(HttpWebRequest req)
        {
            HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();

            Stream dataStm = rsp.GetResponseStream();
            StreamReader rdr = new StreamReader(dataStm);

            string data = rdr.ReadToEnd();

            rdr.Close();
            dataStm.Close();
            rsp.Close();

            return data;
        }

        #endregion

        #region Products

        static string[] ProductTags =
            {
                "<div id='ULLABEL",
                "<div id='LASTSPOT",
                "<div id='SENSE",
                "<div id='STRIKE",
                "<div id='MATURITY",
                "<div id='PARITY",
                "<div id='BID",
                "<div id='ASK",
                "<div id='BIDASK_1",
                "<div id='MAXTRAD",
                "<div id='SYMBOL",
            };

        SGDataModel.SnapshotDataTable GetProducts(string products)
        {
            int offset = 0;

            var data = new SGDataModel.SnapshotDataTable();

            while (-1 != (offset = products.IndexOf(ProductTags[0], offset)))
            {
                SGDataModel.SnapshotRow row = data.NewSnapshotRow();

                int start = products.IndexOf(">", offset) + 1;
                int end = products.IndexOf("<", start);
                string ul = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[1], end);
                row.Underlyer = ul;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string ulSpot = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[2], end);
                row.Price = ulSpot;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string sense = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[3], end);
                row.Type = sense;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string strike = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[4], end);
                row.Strike = strike;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string maturity = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[5], end);
                row.Maturity = maturity;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string parity = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[6], end);
                row.Parity = parity;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string bid = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[7], end);
                row.Bid = bid;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string ask = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[8], end);
                row.Ask = ask;

                start = products.IndexOf(">", offset) + 1;
                start = products.IndexOf(">", start) + 1;
                end = products.IndexOf("<", start);
                string bidask1 = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[9], end);
                row.BidAsk1 = bidask1;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string maxtrad = products.Substring(start, end - start);
                offset = products.IndexOf(ProductTags[10], end);
                row.Issue = maxtrad;

                start = products.IndexOf(">", offset) + 1;
                end = products.IndexOf("<", start);
                string symbol = products.Substring(start, end - start);
                row.Symbol = symbol;

                data.AddSnapshotRow(row);
                data.AcceptChanges();

                Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}",
                    ul, ulSpot, sense, strike, maturity, parity, bid, ask, bidask1, maxtrad, symbol);
            }

            return data;
        }
        #endregion

        #region Get Price Updates

        SGDataModel.SnapshotDataTable GetPriceUpdates(string upd)
        {
            SGDataModel.SnapshotDataTable newData = null;
            int offset = upd.IndexOf("<script>listCodes[");

            if (-1 != offset)
            {
                lock (_Lock)
                {
                    newData = (SGDataModel.SnapshotDataTable)_Snapshot.Copy();
                }

                while (-1 != (offset = upd.IndexOf("listCodes[", offset)))
                {
                    int start = offset;
                    string code = upd.Substring(start, (offset = upd.IndexOf(";", offset)) - start);
                    string codeVl = code.Substring(code.IndexOf("\"") + 1, code.Length - (2 + code.IndexOf("\"")));

                    SGDataModel.SnapshotRow[] rows = (SGDataModel.SnapshotRow[])newData.Select(string.Format("Symbol='{0}'", codeVl));
                    if (null != rows && 0 < rows.Length)
                    {
                        start = offset += 1;
                        string bid = upd.Substring(start, (offset = upd.IndexOf(";", offset)) - start);
                        string bidVl = bid.Substring(bid.IndexOf("= ") + 1, bid.Length - (1 + bid.IndexOf("= ")));
                        rows[0].Bid = bidVl;

                        start = offset += 1;
                        string ask = upd.Substring(start, (offset = upd.IndexOf(";", offset)) - start);
                        string askVl = ask.Substring(ask.IndexOf("= ") + 1, ask.Length - (1 + ask.IndexOf("= ")));
                        rows[0].Ask = askVl;

                        start = offset += 1;
                        string perf = upd.Substring(start, (offset = upd.IndexOf(";", offset)) - start);
                        string perfVl = perf.Substring(perf.IndexOf("= ") + 1, perf.Length - (1 + perf.IndexOf("= ")));
                        rows[0].BidAsk1 = perfVl;

                        Console.WriteLine("{0}\t{1}\t{2}\t{3}",
                            codeVl,
                            bidVl,
                            askVl,
                            perfVl);
                    }
                }

                lock (_Lock)
                {
                    _Snapshot = (SGDataModel.SnapshotDataTable)newData.Copy();
                }
            }

            return newData;
        }

        #endregion
    }
}

